package org.jeecg.common.rc.base64aop;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import org.jeecg.common.util.Vars;
import org.jeecg.common.util.minio.MinioUtil;
import org.jeecg.crud.sys.api.CommonAPI;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * dict aop4
 *
 * @author zjarlin
 * @since 2023/03/25
 */
@Aspect
@Component
@Slf4j
//@SuppressWarnings("all")
public class MinioAop {

    /**
     * 实体上带有注解的翻译成中文
     * 使用了字节码技术新的返回对象其实是obj的子类
     *
     * @param obj 记录
     */

    @Autowired
    private CommonAPI commonAPI;

    @Pointcut("execution(* org.jeecg..BaseController.*(..))")
    public void p1() {
    }

    @Pointcut("execution(* org.jeecg..*Controller+.*(..))")
    public void p2() {
    }

    @Pointcut("execution(* org.jeecg..*Api+.*(..))")
    public void p3() {
    }

    /**
     * 该切面会对实体中属性加了@DictCode2Name注解的字段生效,支持嵌套List<T>属性 T中加了注解的也会被翻译
     * Result<?>对于包装内里的类型,改变内容,aop源码中会对最外层包装类进行类型强转(Result<?>),不会报错
     *
     * @param pjp           pjp
     * @param base64ToMinio 需要翻译
     * @return {@link Object }
     * @author zjarlin
     * @since 2023/01/05
     */
    @Around("(p1()||p2()||p3()) &&  @annotation(base64ToMinio)")
    @SneakyThrows
    public Object minioHandler(ProceedingJoinPoint pjp, Base64ToMinio base64ToMinio) {
        Object[] args = pjp.getArgs();
        Object arg = args[0];
        Class<?> aClass = arg.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        Arrays.stream(declaredFields)
            .peek(field -> field.setAccessible(true))
            .filter(field -> field.getType().isAssignableFrom(String.class))
            .filter(field -> Objects.nonNull(ReflectUtil.getFieldValue(arg, field)))
            .filter(field -> !Modifier.isStatic(field.getModifiers()))
            .filter(field -> field.isAnnotationPresent(Base64ToMinio.class))
            .filter(field -> {
                String base64String = (String) ReflectUtil.getFieldValue(arg, field);
                base64String = base64String.replaceFirst("data:(.+?);base64,", "");
                return StrUtil.isNotBlank(base64String) && cn.hutool.core.codec.Base64.isBase64(base64String);
            })
            .forEach(field -> {
                String name = field.getName();

                String base64String = (String) ReflectUtil.getFieldValue(arg, field);
                base64String = base64String.replaceFirst("data:(.+?);base64,", "");

                byte[] decodedBytes = Base64.getMimeDecoder().decode(base64String.getBytes());
                ByteArrayInputStream stream = new ByteArrayInputStream(decodedBytes);
                String fileName = UUID.randomUUID().toString();
                String upload;
                try {
                    upload = MinioUtil.upload(stream, Vars.datePrefix + "/" + fileName);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                ReflectUtil.setFieldValue(aClass, field, upload);
            });
        Object proceed = pjp.proceed();
        return proceed;
    }

    //@Lazy

}
